/**
 * Copyright (c) 2006-2020, zwl
 * 
 * description   通用设备框架。设备操作，创建，打卡，等
 * 
 * Change Logs:
 * Date             Author         Notes
 * 2021/01/07       Zwl             创建
 * 
 */
#include "EntTypeFramework.h"

/* 容器事件类型对象 */
static struct etf_object_information *          device_information   = ETF_NULL;

#define device_init                         (dev->ops->init)
#define device_open                         (dev->ops->open)
#define device_close                        (dev->ops->close)
#define device_read                         (dev->ops->read)
#define device_write                        (dev->ops->write)
#define device_control                      (dev->ops->control)

/* 设备类型字符串表 */
char                                            etf_device_class_type_table[][15] = {
    "Char",                                             /**< character device */
    "Block",                                            /**< block device */
    "NetIf",                                            /**< net interface */
    "MTD",                                              /**< memory device */
    "CAN",                                              /**< CAN device */
    "RTC",                                              /**< RTC device */
    "Sound",                                            /**< Sound device */
    "Graphic",                                          /**< Graphic device */
    "I2CBUS",                                           /**< I2C bus device */
    "USBDevice",                                        /**< USB slave device */
    "USBHost",                                          /**< USB host bus */
    "SPIBUS",                                           /**< SPI bus device */
    "SPIDevice",                                        /**< SPI device */
    "SDIO",                                             /**< SDIO bus device */
    "PM",                                               /**< PM pseudo device */
    "Pipe",                                             /**< Pipe device */
    "Portal",                                           /**< Portal device */
    "Timer",                                            /**< Timer device */
    "Miscellaneous",                                    /**< Miscellaneous device */
    "Sensor",                                           /**< Sensor device */
    "Touch",                                            /**< Touch device */
    "Unknown"                                           /**< unknown device */
};

/**
 *  设备模块初始化。使能设备框架的时候需要先初始化
 *
 *@param :
 *
 *@return:
 *
 *@note  : 
 *
 *
 */
void etf_device_module_init(void){

    /* 从对象容器中获得对应类型的节点头(协程链表节点头) */
    device_information                              = etf_object_get_information(ETF_Object_Class_Device);
    ETF_IN_ASSERT(ETF_NULL != device_information);
}

/**
 * 设备注册
 *
 *@param :  dev     ：设备对象；
 *          name    ：设备名；
 *          flags   ：设备标志
 *
 *@return:
 *
 *@note  : 
 *          把设备对象链表节点注册到对象容器对应类型的链表中
 *
 */
etf_err_t etf_device_register(etf_device_t dev, const char *name, etf_uint16_t flags){

    ETF_IN_ASSERT(ETF_Device_Class_Unknown >= dev->type);
    
    if (dev == ETF_NULL)
        return (-ETF_ERROR);

    /* 设备是否已经存在 */
    if (etf_device_find(name) != ETF_NULL){

        if( (ETF_TRUE == etf_object_is_systemobject(&(dev->parent))) && 
            (ETF_Object_list_state_suspend_list == etf_object_get_state(&(dev->parent))) &&
            (ETF_Object_Class_Device == etf_object_get_type(&(dev->parent))) ){
            /* 已经存在设备，并初始化过，现在被挂起。则，恢复到运行 */
            goto exit_lp;
        } else {
            return (-ETF_ERROR);
        }
    }

    etf_object_init(&(dev->parent), ETF_Object_Class_Device, name);
exit_lp:    
    dev->flag                                       = flags;
    dev->ref_count                                  = 0;
    dev->open_flag                                  = 0;

    /* 转换到运行链表中 */
    if(ETF_EOK != etf_object_change_to_run_list(&(dev->parent))){
        return (-ETF_ERROR);
    }
    
    return ETF_EOK;
}

/**
 * 删除注册的设备
 *
 * @param 需要删除的设备
 *
 * @return 错误码, ETF_EOK 是成功.
 */
etf_err_t etf_device_unregister(etf_device_t dev){
    //检查传入的对象句柄是否为空
    ETF_IN_ASSERT(dev != ETF_NULL);
    //检查传入的对象是否为设备类型
    ETF_IN_ASSERT(etf_object_get_type(&dev->parent) == ETF_Object_Class_Device);
    //检查传入的对象是否是系统对象(是否是已经注册到对象容器中的对象)
//    ETF_IN_ASSERT(etf_object_is_systemobject(&dev->parent));

    /* 转到挂起队列 */
    if(ETF_EOK != etf_object_change_to_suspend_list(&(dev->parent)) ){
        return (-ETF_ERROR);
    }
    //从对象容器中分离，解除注册
//    etf_object_detach(&(dev->parent));

    return ETF_EOK;
}

/**
 *  通过设备名查找设备对象
 *
 *@param :  name：设备名；
 *
 *@return:  设备对象句柄
 *
 *@note  : 
 *
 *
 */
etf_device_t etf_device_find(const char *name){
    struct etf_object *                     object;
    struct etf_list_node *                  node;
    struct etf_object_information *         information;

    ETF_IN_ASSERT(ETF_NULL != device_information);
    /* 在对象容器中查找到相应类型对象的链表头 */
    information                                     = device_information;
    /* 检查查找结果，容器中是否有这个类型的对象链表 */
    ETF_IN_ASSERT(information != ETF_NULL);
    
    for(node = information->object_run_list.next; node != &(information->object_run_list); node = node->next){
        /* 获取节点对象 */
        object                                      = etf_list_entry(node, struct etf_object, list);
        if (etf_strncmp(object->name, name, ETF_OBJ_NAME_MAX) == 0){
            //对比名字相等，返回对象句柄
            return (etf_device_t)object;
        }
    }

    for(node = information->object_suspend_list.next; node != &(information->object_suspend_list); node = node->next){
        /* 获取节点对象 */
        object                                      = etf_list_entry(node, struct etf_object, list);
        if (etf_strncmp(object->name, name, ETF_OBJ_NAME_MAX) == 0){
            //对比名字相等，返回对象句柄
            return (etf_device_t)object;
        }
    }

    /* not found */
    return ETF_NULL;
}

/**
 * 初始化制定设备
 *
 *@param :  dev：设备对象句柄；
 *
 *@return:  结果
 *
 *@note  : 
 *
 *
 */
etf_err_t rt_device_init(etf_device_t dev){

    etf_err_t result                                = ETF_EOK;

    ETF_IN_ASSERT(dev != ETF_NULL);

    /* 获取设备初始化句柄 */
    if (device_init != ETF_NULL){
        /* 检查设备标志，判断设备是否是被激活的 */
        if (!(dev->flag & ETF_DEVICE_FLAG_ACTIVATED)){
            //设备是未激活的，进行初始化
            result                                  = device_init(dev);
            if(result != ETF_EOK){
                etf_printf("To initialize device:%s failed. The error code is %d\n", dev->parent.name, result);
            } else {
                /* 初始化成功，设备设置为激活状态 */
                dev->flag                          |= ETF_DEVICE_FLAG_ACTIVATED;
            }
        }
    }

    return result;
}

/**
 * 打开一个设备
 *
 *@param :  dev     ：设备对象句柄；
 *          oflag   ：设备标志
 *@return:  结果
 *
 *@note  : 
 *
 *
 */
etf_err_t etf_device_open(etf_device_t dev, etf_uint16_t oflag){

    etf_err_t   result                              = ETF_EOK;

    ETF_IN_ASSERT(dev != ETF_NULL);
    /* 检查对象类型是否是设备 */
    ETF_IN_ASSERT(etf_object_get_type(&dev->parent) == ETF_Object_Class_Device);

    /* 如果设备未初始化，先初始化 */
    if (!(dev->flag & ETF_DEVICE_FLAG_ACTIVATED)){
        /* 调用设备初始化接口 */
        if (device_init != ETF_NULL){
            result                                  = device_init(dev);
            if (result != ETF_EOK){
                etf_printf("To initialize device:%s failed. The error code is %d\n", dev->parent.name, result);

                return result;
            }
        }

        dev->flag                                  |= ETF_DEVICE_FLAG_ACTIVATED;
    }

    /* 设备是独立的或已经打开的返回忙 */
    if ((dev->flag & ETF_DEVICE_FLAG_STANDALONE) && (dev->open_flag & ETF_DEVICE_OFLAG_OPEN)){
        return -ETF_EBUSY;
    }

    /* 调用设备打开接口 */
    if (device_open != ETF_NULL){
        result                                      = device_open(dev, oflag);
    } else {
        /* 设备不能打开，清除标志 */
        dev->open_flag                              = (oflag & ETF_DEVICE_OFLAG_MASK);
    }

    
    if ( (result == ETF_EOK) || (result == (-ETF_ENOSYS)) ){
        /* 成功打开设置打开标志 */
        dev->open_flag                             |= ETF_DEVICE_OFLAG_OPEN;

        dev->ref_count++;
        /* don't let bad things happen silently. If you are bitten by this assert,
         * please set the ref_count to a bigger type. */
        ETF_IN_ASSERT(dev->ref_count != 0);
    }

    return result;
}

/**
 * 关闭一个设备
 *
 *@param :  dev：设备对象句柄；
 *
 *@return:  结果
 *
 *@note  : 
 *
 *
 */
etf_err_t etf_device_close(etf_device_t dev){

    etf_err_t           result                      = ETF_EOK;

    ETF_IN_ASSERT(dev != ETF_NULL);
    /* 设备对象是否是设备类型 */
    ETF_IN_ASSERT(etf_object_get_type(&dev->parent) == ETF_Object_Class_Device);

    /* 设备未被打开，关闭错误 */
    if (dev->ref_count == 0)
        return -ETF_ERROR;

    dev->ref_count--;

    /* 设备关闭完成，因为多次开启 */
    if (dev->ref_count != 0)
        return ETF_EOK;

    /* 调用设备关闭接口 */
    if (device_close != ETF_NULL){
        result                                      = device_close(dev);
    }

    /* 设置打开标志位关闭 */
    if (result == ETF_EOK || result == -ETF_ENOSYS)
        dev->open_flag                              = ETF_DEVICE_OFLAG_CLOSE;

    return result;
}

/**
 * 从设备中读取数据
 *
 *@param :  dev     ：设备对象句柄；
 *          pos     ：读取位置；
 *          buffer  ：保存读取数据的地址；
 *          size    ：读取的尺寸；
 *@return:  读取到的数据尺寸
 *
 *@note  : 
 *
 *
 */
etf_size_t etf_device_read(etf_device_t dev, etf_off_t pos, void *buffer, etf_size_t size){

    ETF_IN_ASSERT(dev != ETF_NULL);
    ETF_IN_ASSERT(etf_object_get_type(&dev->parent) == ETF_Object_Class_Device);

    /* 设备未被引用(未打卡) */
    if (dev->ref_count == 0){
        /* 未打开，返回0 */
        return 0;
    }

    /* 调用设备读接口 */
    if (device_read != ETF_NULL){
        return device_read(dev, pos, buffer, size);
    }

    /* 未打开，返回0 */
    return 0;
}

/**
 * 往设备中写入数据
 *
 *@param :  dev     ：设备对象句柄；
 *          pos     ：写入位置；
 *          buffer  ：需要写入的数据存放地址；
 *          size    ：需要写入的数据尺寸；
 *@return:  成功写入的数据尺寸
 *
 *@note  : 
 *
 *
 */
etf_size_t etf_device_write(etf_device_t dev, etf_off_t pos, const void *buffer, etf_size_t size){

    ETF_IN_ASSERT(dev != ETF_NULL);
    ETF_IN_ASSERT(etf_object_get_type(&dev->parent) == ETF_Object_Class_Device);

    /* 设备未被引用(未打卡) */
    if (dev->ref_count == 0){
        /* 未打开，返回0 */
        return 0;
    }

    /* 调用设备写入接口 */
    if(device_write != ETF_NULL){
        return device_write(dev, pos, buffer, size);
    }

    /* 未打开，返回0 */
    return 0;
}

/**
 * 控制设备各种功能
 *
 *@param :  dev：设备对象句柄；
 *          cmd：控制设备的指令；
 *          arg：指令参数；
 *
 *@return:  结果
 *
 *@note  : 
 *
 *
 */
etf_err_t etf_device_control(etf_device_t dev, etf_uint32_t cmd, void *arg){
    ETF_IN_ASSERT(dev != ETF_NULL);
    ETF_IN_ASSERT(etf_object_get_type(&dev->parent) == ETF_Object_Class_Device);

    /* 调用控制设备接口 */
    if (device_control != ETF_NULL)
    {
        return device_control(dev, cmd, arg);
    }

    return -ETF_ENOSYS;
}

/**
 * 中断接收模式下。这个函数将设置接收回调函数。当设备接收到数据时调用这个函数。
 * 
 *@param :  dev     ：设备对象句柄；
 *          *rx_ind ：回调函数指针；
 *
 *@return:  结果
 *
 *@note  : 
 *
 *
 */
etf_err_t etf_device_set_rx_indicate(etf_device_t dev, etf_err_t (*rx_ind)(etf_device_t dev, etf_size_t size)){
    ETF_IN_ASSERT(dev != ETF_NULL);
    ETF_IN_ASSERT(etf_object_get_type(&dev->parent) == ETF_Object_Class_Device);

    dev->rx_indicate                                = rx_ind;

    return ETF_EOK;
}

/**
 * 设置发送完成回调函数。
 *
 *@param :
 *
 *@return:
 *
 *@note  : 
 *
 *
 */
etf_err_t etf_device_set_tx_complete(etf_device_t dev, etf_err_t (*tx_done)(etf_device_t dev, void *buffer)){
    ETF_IN_ASSERT(dev != ETF_NULL);
    ETF_IN_ASSERT(etf_object_get_type(&dev->parent) == ETF_Object_Class_Device);

    dev->tx_complete                                = tx_done;

    return ETF_EOK;
}


